﻿using IdentityModel;
using IdentityServer4;
using IdentityServer4.Events;
using IdentityServer4.Extensions;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SX.AuthServer.Data;
using SX.AuthServer.Models;
using SX.AuthServer.ViewModel;
using SX.Core;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace SX.AuthServer.Controllers
{
    [Route("[controller]/[action]")]
    public class AccountController:Controller
    {
        private readonly IIdentityServerInteractionService _interaction;
        private readonly IEventService _events;
        private readonly AppSettings _appSettings;
        private readonly ApplicationDbContext _dbContext;
        public AccountController(IIdentityServerInteractionService identityServerInteractionService,IEventService eventService,AppSettings appSettings, ApplicationDbContext applicationDbContext)
        {
            _dbContext = applicationDbContext;
            _interaction = identityServerInteractionService;
            _events = eventService;
            _appSettings = appSettings;
        }

        /// <summary>
        /// 登录页面
        /// </summary>
        [HttpGet]
        public async Task<IActionResult> Login(string returnUrl)
        {
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
            if (context?.IdP != null)
            {
                throw new NotImplementedException("External login is not implemented!");
            }
            returnUrl = returnUrl ?? _appSettings.AdminUI.RedirectUris.First().Replace("/callback", "");
            var loginViewModal = new LoginInput { ReturnUrl = returnUrl };
            return View(loginViewModal);
        }

        /// <summary>
        /// 登录接口
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IApiResult> Login(LoginInput input)
        {
            if (!ModelState.IsValid)
            {
                return ApiResult.NotOk(ModelState.Values.First().Errors[0].ErrorMessage);
            }
            var context = await _interaction.GetAuthorizationContextAsync(input.ReturnUrl);
            var user = _dbContext.Set<ApplicationUser>().Where(x => x.UserName == input.UserName).Select(a=> new{ a.Id,a.Password}).FirstOrDefault();
            if (user == null)
            {
                return ApiResult.NotOk("用户信息不存在", 1);
            }

            var password = Md5Encrypt.Encrypt32(input.Password);
            if (user.Password != password)
            {
                return ApiResult.NotOk("密码错误", 2);
            }


            AuthenticationProperties props = null;
            if (input.RememberLogin)
            {
                props = new AuthenticationProperties
                {
                    IsPersistent = true,
                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1))
                };
            };

            var identityServerUser = new IdentityServerUser(user.Id.ToString())
            {
                DisplayName = input.UserName
            };
            await HttpContext.SignInAsync(identityServerUser, props);
            if (_interaction.IsValidReturnUrl(input.ReturnUrl))
            {
                //return Redirect(input.ReturnUrl);
            }
            //return Redirect("~/");
            return ApiResult.Ok("");
        }
        /// <summary>
        /// 退出登录
        /// </summary>
        /// <param name="logoutId"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> LoginOut(string logoutId)
        {
            var vm = await BuildLogoutViewModelAsync(logoutId);

            if (vm.ShowLogoutPrompt == false)
            {
                return await LoginOut(vm);
            }

            //强制跳到客户端界面
            var postLogoutRedirectUri = _appSettings.AdminUI.PostLogoutRedirectUris.First();
            if (!string.IsNullOrWhiteSpace( postLogoutRedirectUri))
            {
                return Redirect(postLogoutRedirectUri);
            }
            return RedirectToAction("Login");
        }
        
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> LoginOut(LogoutInputModel model)
        {
            try
            {
                var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);

                if (User?.Identity.IsAuthenticated == true)
                {
                    await HttpContext.SignOutAsync();

                    await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
                }

                if (vm.TriggerExternalSignout)
                {
                    string url = Url.Action("Logout", new { logoutId = vm.LogoutId });

                    return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
                }

                var postLogoutRedirectUri = vm.PostLogoutRedirectUri == null ? _appSettings.AdminUI.PostLogoutRedirectUris.First() : vm.PostLogoutRedirectUri;
                if (vm.AutomaticRedirectAfterSignOut)
                {
                    return Redirect(postLogoutRedirectUri);
                }
                //强制跳到客户端界面
                if (!string.IsNullOrWhiteSpace(postLogoutRedirectUri))
                {
                    return Redirect(postLogoutRedirectUri);
                }

                return RedirectToAction("Login");
            }
            catch(Exception ex)
            {
                return RedirectToAction("Login");
            }
        }

        private async Task<LogoutViewModel> BuildLogoutViewModelAsync(string logoutId)
        {
            var vm = new LogoutViewModel { LogoutId = logoutId, ShowLogoutPrompt = AccountOptions.ShowLogoutPrompt };

            if (User?.Identity.IsAuthenticated != true)
            {
                vm.ShowLogoutPrompt = false;
                return vm;
            }

            var context = await _interaction.GetLogoutContextAsync(logoutId);
            if (context?.ShowSignoutPrompt == false)
            {
                vm.ShowLogoutPrompt = false;
                return vm;
            }

            return vm;
        }
        private async Task<LoggedOutViewModel> BuildLoggedOutViewModelAsync(string logoutId)
        {
            var logout = await _interaction.GetLogoutContextAsync(logoutId);

            var vm = new LoggedOutViewModel
            {
                AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
                PostLogoutRedirectUri = logout?.PostLogoutRedirectUri,
                ClientName = string.IsNullOrEmpty(logout?.ClientName) ? logout?.ClientId : logout?.ClientName,
                SignOutIframeUrl = logout?.SignOutIFrameUrl,
                LogoutId = logoutId
            };

            if (User?.Identity.IsAuthenticated == true)
            {
                var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
                if (idp != null && idp != IdentityServerConstants.LocalIdentityProvider)
                {
                    var providerSupportsSignout = await HttpContext.GetSchemeSupportsSignOutAsync(idp);
                    if (providerSupportsSignout)
                    {
                        if (vm.LogoutId == null)
                        {
                            vm.LogoutId = await _interaction.CreateLogoutContextAsync();
                        }

                        vm.ExternalAuthenticationScheme = idp;
                    }
                }
            }
            return vm;
        }
    }
}
